﻿using System;
using System.Collections.Generic;
using System.Data.Services.Client;
using System.Linq;
using nRoute.Components;
using nRoute.Components.Composition;
using nRoute.Navigation.Mapping;
using nRoute.Samples.Netflix.Data;
using nRoute.Samples.Netflix.Data.Catalog;
using nRoute.Samples.Netflix.Views;
using nRoute.ViewModels;

namespace nRoute.Samples.Netflix.ViewModels
{
    [DefineNavigationContent("Content/Netflix/Titles/", typeof(TitlesListingView))]
    [MapViewModel(typeof(TitlesListingView))]    
    public class TitlesListingViewModel
        : NavigationViewModelBase
    {
        private const int PAGE_SIZE = 20;
        private const string MOVIE_TITLES_KEY = "MovieTitles";
        private const string PAGE_TITLE_KEY = "PageTitle";
        private const string LAST_PAGEINDEX_KEY = "LastPageIndex";

        private DataServiceCollection<Title> _titles;
        private NetflixDataContext _context;

        [ResolveConstructor]
        public TitlesListingViewModel(NetflixDataContext context)
        {
            _context = context;
            SetupCommands();            
        }

#region Properties

        public IEnumerable<Title> Titles
        {
            get { return _titles.Skip(PAGE_SIZE * (CurrentPageIndex - 1)).Take(PAGE_SIZE); }
        }

        public bool IsLoading { get; private set; }

        public ActionCommand NextPageCommand { get; private set; }

        public ActionCommand PreviousPageCommand { get; private set; }

        public int CurrentPageIndex { get; private set; }

#endregion

#region Overrides

        protected override void OnIntialize(ParametersCollection state)
        {
            base.Title = Convert.ToString(state[PAGE_TITLE_KEY]);

            // if there is last page index data, it means it will be restored from state
            if (!state.ContainsKey(LAST_PAGEINDEX_KEY)) SetupTitles((DataServiceCollection<Title>)state[MOVIE_TITLES_KEY], 1);            
        }

        protected override void OnRestoreState(ParametersCollection state)
        {
            // if movie titles are already loaded we don't load again
            if (state == null) return;

            if (state.ContainsKey(MOVIE_TITLES_KEY))
            {
                base.Title = Convert.ToString(state[PAGE_TITLE_KEY]);
                NotifyPropertyChanged(() => Title);
                SetupTitles((DataServiceCollection<Title>)state[MOVIE_TITLES_KEY], Convert.ToInt32(state[LAST_PAGEINDEX_KEY]));
            }
            else
            {
                // inform no loaded data
            }
        }

        protected override ParametersCollection OnSaveState()
        {
            if (_titles != null)
            {
                _titles.LoadCompleted -= Titles_LoadCompleted;
                return new ParametersCollection() 
                { 
                    new Parameter(MOVIE_TITLES_KEY, _titles), 
                    new Parameter(PAGE_TITLE_KEY, base.Title),
                    new Parameter(LAST_PAGEINDEX_KEY, CurrentPageIndex)
                };
            }
            else
            {
                return null;
            }
        }

#endregion

#region Helpers

        private void SetupCommands()
        {
            this.NextPageCommand = new ActionCommand(() =>
            {
                CurrentPageIndex += 1;
                NotifyPropertyChanged(() => CurrentPageIndex);
                UpdatePageIndexedTitles();
            });

            this.PreviousPageCommand = new ActionCommand(() =>
            {
                CurrentPageIndex -= 1;
                NotifyPropertyChanged(() => CurrentPageIndex);
                UpdatePageIndexedTitles();
            });
        }

        private void SetupTitles(DataServiceCollection<Title> titles, int pageIndex)
        {
            _titles = titles;
            _titles.LoadCompleted += Titles_LoadCompleted;
            NotifyPropertyChanged(() => Titles);

            CurrentPageIndex = pageIndex;
            NotifyPropertyChanged(() => CurrentPageIndex);

            if (_titles.Count == 0)
            {
                IsLoading = true;
                NotifyPropertyChanged(() => IsLoading);

                try
                {
                    _titles.LoadAsync();
                }
                catch { }
            }
            else
            {
                NotifyPropertyChanged(() => Titles);
                UpdatePageIndexedTitles();
            }
        }

        private void Titles_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            IsLoading = false;
            NotifyPropertyChanged(() => IsLoading);
            UpdatePageIndexedTitles();
        }

        private void UpdatePageIndexedTitles()
        {
            if (CurrentPageIndex * PAGE_SIZE >= _titles.Count)
            {
                if (_titles.Continuation != null)
                {
                    IsLoading = true;
                    NotifyPropertyChanged(() => IsLoading);
                    if (!_titles.LoadNextPartialSetAsync()) UpdatePageIndexedTitles();
                    return;
                }
                else
                {
                    NextPageCommand.IsActive = false;
                }
            }
            else
            {
                NextPageCommand.IsActive = true;
            }

            PreviousPageCommand.IsActive = (CurrentPageIndex != 1);
            NotifyPropertyChanged(() => Titles);
        }

#endregion

    }
}